﻿using DevExpress.Utils.Drawing;
using DevExpress.XtraEditors.CustomEditor;
using DevExpress.XtraEditors.Drawing;
using DevExpress.XtraEditors.Registrator;
using DevExpress.XtraEditors.Repository;
using DevExpress.XtraEditors.ViewInfo;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Reflection;


namespace DotNetExtensions.AspNet.DevExpress.Repositories
{
    public class PartitionColorBarControlEditPainter : AnyControlEditPainter
    {
        public PartitionColorBarControlEditPainter()
        {

        }
        public PartitionColorBarControlEditBackColor BackColors { get; set; }
        public Func<object, List<PartitionColorBarControlEditValueItem>> ValueProvider { get; set; }

        public PartitionColorBarControlEditPainter(PartitionColorBarControlEditBackColor backColors)
        {
            BackColors = backColors;
        }


        private readonly Color DefaultBrushColor = Color.Gray;

        protected override void DrawContent(ControlGraphicsInfoArgs info)
        {
            info.ViewInfo.PaintAppearance.BackColor = Color.White;
            info.ViewInfo.PaintAppearance.DrawBackground(info.Cache, info.Bounds);

            if (ValueProvider != null) DrawColorPanel(info);
            else
            {
                info.ViewInfo.PaintAppearance.DrawString(info.Cache, info.ViewInfo.DisplayText, info.Bounds);
            }
        }
        private void DrawColorPanel(ControlGraphicsInfoArgs info)
        {
            List<PartitionColorBarControlEditValueItem> items = ValueProvider?.Invoke(info.ViewInfo.DisplayText);

            string text = info.ViewInfo.DisplayText;
            int panelCount = items.Count;
            Point start = info.Bounds.Location;
            int width = info.Bounds.Width / panelCount;
            int residue = info.Bounds.Width - width * panelCount;

            int[] widths = new int[panelCount];
            for (int i = 0; i < panelCount; i++)
            {
                if (i == panelCount - 1) widths[i] = width + residue;
                else widths[i] = width;
            }

            Rectangle[] rects = new Rectangle[panelCount];
            for (int i = 0; i < panelCount; i++)
            {

                PartitionColorBarControlEditValueItem item = items[i];
                PartitionColorBarControlEditValueItem nextItem = i < panelCount - 1 ? items[i + 1] : null;

                Brush rectBrush = new SolidBrush(DefaultBrushColor);
                Color polygonBrushColor = DefaultBrushColor;
                if (nextItem == null && BackColors.Items.Any(bc => bc.Index == item.ColorIndex))
                {
                    rectBrush = new SolidBrush(BackColors.Items.First(bc => bc.Index == item.ColorIndex).BackColor);
                }
                else if (nextItem != null && BackColors.Items.Any(bc => bc.Index == nextItem.ColorIndex))
                {
                    rectBrush = new SolidBrush(BackColors.Items.First(bc => bc.Index == nextItem.ColorIndex).BackColor);
                }

                if (BackColors.Items.Any(bc => bc.Index == item.ColorIndex))
                {
                    polygonBrushColor = BackColors.Items.First(bc => bc.Index == item.ColorIndex).BackColor;
                }

                int boundWith = info.Bounds.Width;
                int boundHeight = info.Bounds.Height;

                int brushIndex = item.ColorIndex;
                string displayText = item.DisplayText;
                Font textFont = new Font("Tahoma", 12);


                Point rectLocation = new Point(start.X + i * width, start.Y);
                rects[i] = new Rectangle(rectLocation, new Size(widths[i], info.Bounds.Height));

                var displayTextSize = info.Cache.Graphics.MeasureString(displayText, textFont);

                float fx = rects[i].X + (widths[i] - displayTextSize.Width) / 2;
                float fy = rects[i].Y + (rects[i].Height - displayTextSize.Height) / 2;

                Point fp = new Point(Convert.ToInt32(fx), Convert.ToInt32(fy));

                info.Cache.FillRectangle(rectBrush, rects[i]);

                Point a = new Point(rectLocation.X + widths[i] - 5, rectLocation.Y);
                Point b = new Point(rectLocation.X + widths[i] - 5, rectLocation.Y + info.Bounds.Height);
                Point c = new Point(rectLocation.X + widths[i], rectLocation.Y + (b.Y - a.Y) / 2);

                Point e = new Point(rectLocation.X, rectLocation.Y);
                Point d = new Point(rectLocation.X, b.Y);

                info.Cache.FillPolygon(new Point[] { e, a, c, b, d, e }, polygonBrushColor);
                info.Cache.DrawString(displayText, textFont, Brushes.White, fp);
            }
        }

    }
    public class PartitionColorBarControlEditViewInfo : AnyControlEditViewInfo, IHeightAdaptable
    {
        public PartitionColorBarControlEditViewInfo(RepositoryItem item) : base(item) { }

        int IHeightAdaptable.CalcHeight(GraphicsCache cache, int width)
        {
            Rectangle textRect = new Rectangle(0, 0, width, 100);
            if (!(BorderPainter is EmptyBorderPainter) && !(BorderPainter is InplaceBorderPainter))
                textRect.Inflate(-1, -1);
            string text = string.Empty;
            {
                text = DisplayText;
                if (text != null && text.Length > 0)
                {
                    char lastChar = text[text.Length - 1];
                    if (lastChar == 13 || lastChar == 10) text += "W";
                }
            }
            int height = CalcTextSizeCore(cache, text, textRect.Width).Height + 1;
            return (height + 100 - textRect.Bottom) + 1;
        }
    }
    [ToolboxItem(true)]
    [DesignerCategory("Color Bar")]
    public class PartitionColorBarControlEdit : AnyControlEdit
    {
        static PartitionColorBarControlEdit()
        {
            PartitionColorBarEditRepositoryItem.RegisterCustomAnyControlEdit();
        }

        public PartitionColorBarControlEdit()
        {
        }


        protected internal virtual PartitionColorBarControlEditViewInfo CustomAnyControlViewInfo { get { return ViewInfo as PartitionColorBarControlEditViewInfo; } }

        public override string EditorTypeName
        {
            get { return PartitionColorBarEditRepositoryItem.PartitionColorBarControlEditName; }
        }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public new PartitionColorBarEditRepositoryItem Properties
        {
            get { return base.Properties as PartitionColorBarEditRepositoryItem; }
        }
    }
    public class PartitionColorBarControlEditBackColorItem
    {
        public int Index { get; set; }
        public Color BackColor { get; set; }
        public PartitionColorBarControlEditBackColorItem(int index, Color color)
        {
            Index = index;
            BackColor = color;
        }
    }
    public class PartitionColorBarControlEditValueItem
    {
        public int ColorIndex { get; set; }
        public object Value { get; set; }
        public string DisplayText { get; set; }
        public PartitionColorBarControlEditValueItem() { }
        public PartitionColorBarControlEditValueItem(int colorIndex, object value, string text)
        {
            ColorIndex = colorIndex;
            Value = value;
            DisplayText = text;
        }
    }
    public class PartitionColorBarControlEditBackColor
    {
        public readonly List<PartitionColorBarControlEditBackColorItem> Items = new List<PartitionColorBarControlEditBackColorItem>();

        public void Add(PartitionColorBarControlEditBackColorItem value)
        {
            if (!Items.Any(c => c.Index == value.Index)) Items.Add(value);
        }
        public void AddRange(PartitionColorBarControlEditBackColorItem[] values)
        {
            foreach (var item in values) Add(item);
        }
    }

    public class PartitionColorBarControlEditValue
    {
        public readonly List<PartitionColorBarControlEditBackColorItem> Items = new List<PartitionColorBarControlEditBackColorItem>();
        public void Add(PartitionColorBarControlEditBackColorItem value)
        {
            if (!Items.Any(c => c.Index == value.Index)) Items.Add(value);
        }
        public void AddRange(PartitionColorBarControlEditBackColorItem[] values)
        {
            foreach (var item in values) Add(item);
        }
    }

    [UserRepositoryItem("PartitionColorBarEditRepositoryItem")]
    public class PartitionColorBarEditRepositoryItem : RepositoryItemAnyControl
    {
        public PartitionColorBarEditRepositoryItem()
        {
            colorItems = new PartitionColorBarControlEditBackColor();
            value = new PartitionColorBarControlEditValue();
        }
        private PartitionColorBarControlEditBackColor colorItems;
        private PartitionColorBarControlEditValue value;
        public PartitionColorBarControlEditBackColor ColorItems
        {
            get
            {
                return colorItems;
            }

            private set
            {
                colorItems = value;
                (Painter as PartitionColorBarControlEditPainter).BackColors = colorItems;
                OnPropertiesChanged();
            }
        }

        public PartitionColorBarControlEditValue Value
        {
            get
            {
                return value;
            }

            private set
            {
                this.value = value;
                OnPropertiesChanged();
            }
        }

        private Func<object, List<PartitionColorBarControlEditValueItem>> valueProvider;

        public void AddColorItem(int index, Color color)
        {
            colorItems.Add(new PartitionColorBarControlEditBackColorItem(index, color));
            (Painter as PartitionColorBarControlEditPainter).BackColors = colorItems;
            OnPropertiesChanged();
        }

        public void AddColorItem(PartitionColorBarControlEditBackColorItem item)
        {
            colorItems.Add(item);
            (Painter as PartitionColorBarControlEditPainter).BackColors = colorItems;
            OnPropertiesChanged();
        }

        public void AddColorItem(PartitionColorBarControlEditBackColorItem[] items)
        {
            colorItems.AddRange(items);
            (Painter as PartitionColorBarControlEditPainter).BackColors = colorItems;
            OnPropertiesChanged();
        }

        static PartitionColorBarEditRepositoryItem()
        {
            RegisterCustomAnyControlEdit();
        }

        public const string PartitionColorBarControlEditName = "PartitionColorBarControlEdit";

        public override string EditorTypeName
        {
            get { return PartitionColorBarControlEditName; }
        }

        public static void RegisterCustomAnyControlEdit()
        {
            Image img = null;
            try
            {
                img = (Bitmap)Bitmap.FromStream(Assembly.GetExecutingAssembly().
                    GetManifestResourceStream("DevExpress.CustomEditors.CustomEdit.bmp"));
            }
            catch
            { }

            EditorRegistrationInfo.Default.Editors.Add(new EditorClassInfo(PartitionColorBarControlEditName, typeof(PartitionColorBarControlEdit),
                typeof(PartitionColorBarEditRepositoryItem),
                typeof(PartitionColorBarControlEditViewInfo), new PartitionColorBarControlEditPainter(), true, img));
        }

        public override bool AllowInplaceAutoFilter
        {
            get
            {
                return true;
            }
        }

        public override bool IsFilterLookUp
        {
            get
            {
                return true;
            }
        }

        public override bool UseTextEditorForAutoFilter
        {
            get
            {
                return true;
            }
        }

        public Func<object, List<PartitionColorBarControlEditValueItem>> ValueProvider
        {
            get
            {
                return valueProvider;
            }

            set
            {
                valueProvider = value;
                (Painter as PartitionColorBarControlEditPainter).ValueProvider = valueProvider;
            }
        }

        protected override PropertyDescriptorCollection FilterProperties(PropertyDescriptorCollection collection)
        {
            return base.FilterProperties(collection);
        }

        public override string GetDisplayText(object editValue)
        {
            return base.GetDisplayText(editValue);
        }

        public override void Assign(RepositoryItem item)
        {
            BeginUpdate();
            try
            {
                base.Assign(item);
                PartitionColorBarEditRepositoryItem source = item as PartitionColorBarEditRepositoryItem;
                if (source == null) return;
            }
            finally
            {
                EndUpdate();
            }
        }
    }
}
